
//--YangXin--

`include "defines.v"


module mem_stage(
	input  wire         				clk           ,
	input  wire         				reset         ,
	//allowin
	input  wire         				ws_allowin    ,
	output wire           				ms_allowin    ,
	//from es
	input  wire         				es_to_ms_valid,
	input  wire [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus  ,
	//to ws
	output wire         				ms_to_ws_valid,
	output wire [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus  ,
	//forward
	output wire [                 68:0] ms_to_ds_fwd  ,
	output wire [                128:0] csr_ms_to_es_fwd,
	//from data_sram
	input  wire [                 63:0] data_sram_rdata_d0,
	//except
	input  wire 						except_flush  ,
	output wire [                 63:0] ms_pc_to_ws   ,
	output wire 						ms_valid_to_ws,
	input  wire [                 63:0] mtimecmp_i    ,
	input  wire [                 63:0] mtime_i        
	// input  wire                         es_inst                 
	);

reg          ms_valid;
wire         ms_ready_go;

reg [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus_r;
wire         ms_res_from_mem;
wire         ms_gr_we;
wire [ 4:0]  ms_dest;
wire [63:0]  ms_alu_result;
wire [63:0]  ms_pc;
wire [31:0]  ms_inst;   //difftest
//csr
wire 		 ms_csr_wr;
wire [63:0]  ms_csr_wdata;
wire [11:0]  ms_csr_waddr;
//exception
wire         ms_except_enter_ecall;
wire         ms_except_quit_mret ;

//store load
wire [10:0]  ms_mem_control;
wire         load_sign_lb  ;
wire         load_sign_lh  ;
wire         load_sign_lw  ;
wire [63:0]  mem_result_lb ;
wire [63:0]  mem_result_lb_temp ;


wire [63:0]  mem_result_lh ;
wire [63:0]  mem_result_lh_temp ;

wire [63:0]  mem_result_lw ;
wire [63:0]  mem_result_lw_temp ;

wire [63:0]  mem_result_lbu;
wire [63:0]  mem_result_lhu;
wire [63:0]  mem_result_lwu;
wire [63:0]  mem_result_ld ;

reg  [63:0]  data_sram_rdata;


always @(posedge clk) begin
	data_sram_rdata <= data_sram_rdata_d0;
end



//lb lbu
assign load_sign_lb = (ms_alu_result[2:0] == 3'b000) ? data_sram_rdata[7] :
					  (ms_alu_result[2:0] == 3'b001) ? data_sram_rdata[15]:
					  (ms_alu_result[2:0] == 3'b010) ? data_sram_rdata[23]:
					  (ms_alu_result[2:0] == 3'b011) ? data_sram_rdata[31]:
					  (ms_alu_result[2:0] == 3'b100) ? data_sram_rdata[39]:
					  (ms_alu_result[2:0] == 3'b101) ? data_sram_rdata[47]:
					  (ms_alu_result[2:0] == 3'b110) ? data_sram_rdata[55]:
					  (ms_alu_result[2:0] == 3'b111) ? data_sram_rdata[63]:
					  												  1'b0;

assign mem_result_lb_temp[7:0] = 
					  (ms_alu_result[2:0] == 3'b000) ? data_sram_rdata[7:0] :
					  (ms_alu_result[2:0] == 3'b001) ? data_sram_rdata[15:8]:
					  (ms_alu_result[2:0] == 3'b010) ? data_sram_rdata[23:16]:
					  (ms_alu_result[2:0] == 3'b011) ? data_sram_rdata[31:24]:
					  (ms_alu_result[2:0] == 3'b100) ? data_sram_rdata[39:32]:
					  (ms_alu_result[2:0] == 3'b101) ? data_sram_rdata[47:40]:
					  (ms_alu_result[2:0] == 3'b110) ? data_sram_rdata[55:48]:
					  (ms_alu_result[2:0] == 3'b111) ? data_sram_rdata[63:56]:
					  								   data_sram_rdata[63:56];

assign mem_result_lb  = {{56{load_sign_lb}}, mem_result_lb_temp[7:0]};
assign mem_result_lbu = {56'd0, mem_result_lb_temp[7:0]};

//lh/lhu

assign load_sign_lh = (ms_alu_result[2:1] == 2'b00 ) ? data_sram_rdata[15]:
           			  (ms_alu_result[2:1] == 2'b01 ) ? data_sram_rdata[31]:
           			  (ms_alu_result[2:1] == 2'b10 ) ? data_sram_rdata[47]:
           			  (ms_alu_result[2:1] == 2'b11 ) ? data_sram_rdata[63]:
           			  												  1'b0;

assign mem_result_lh_temp[15:0] = 
					  (ms_alu_result[2:1] == 2'b00 ) ? data_sram_rdata[15:0]:
           			  (ms_alu_result[2:1] == 2'b01 ) ? data_sram_rdata[31:16]:
           			  (ms_alu_result[2:1] == 2'b10 ) ? data_sram_rdata[47:32]:
           			  (ms_alu_result[2:1] == 2'b11 ) ? data_sram_rdata[63:48]:
           			                                   data_sram_rdata[63:48];

assign mem_result_lh  = {{48{load_sign_lh}},mem_result_lh_temp[15:0]};           			  
assign mem_result_lhu = {48'd0, mem_result_lh_temp[15:0]};

//lw/lwu

assign load_sign_lw = (ms_alu_result[2] == 1'b0) ? data_sram_rdata[31] :
					  (ms_alu_result[2] == 1'b1) ? data_sram_rdata[63] :
					  						                   	  1'b0 ;
assign mem_result_lw_temp[31:0] = 
					  (ms_alu_result[2] == 1'b0) ? data_sram_rdata[31: 0]:
					  (ms_alu_result[2] == 1'b0) ? data_sram_rdata[63:32]:
					  							   data_sram_rdata[63:32];

assign mem_result_lw = {{32{load_sign_lw}}, mem_result_lw_temp[31:0]};
assign mem_result_lwu = {32'd0, mem_result_lw_temp[31:0]};

//ld
assign mem_result_ld = data_sram_rdata;




wire [4:0]   MEM_dest;
assign MEM_dest = ms_dest & {5{ms_valid}};

wire ms_skip;
wire ms_skip_mtime;
wire ms_skip_mtimecmp;

//forward
//wire [68:0]  ms_to_ds_fwd;
assign ms_to_ds_fwd     = {69{ms_valid}} & {69{ms_gr_we}} & {ms_dest,ms_final_result};  //5+64
assign csr_ms_to_es_fwd = {129{ms_valid}} & {129{ms_csr_wr}} & 
						  {ms_csr_wr,ms_csr_waddr,ms_csr_wdata}; //1+64+64
assign {ms_skip_mtimecmp     ,
		ms_skip_mtime        ,
	    ms_skip              ,
		ms_except_enter_ecall,
		ms_except_quit_mret ,
		ms_csr_wr      ,
		ms_csr_wdata   ,
		ms_csr_waddr   ,
		ms_inst        ,
		ms_mem_control ,    
		ms_res_from_mem,
	    ms_gr_we       ,
	    ms_dest		   ,
	    ms_alu_result  ,
	    ms_pc
	    } = es_to_ms_bus_r;

wire [63:0] mem_result;
wire [63:0] ms_final_result;

assign ms_to_ws_bus = {ms_skip              , //245:245
					   ms_except_enter_ecall, //244:244
					   ms_except_quit_mret , //243:243
					   ms_csr_wr      ,  //242:242
					   ms_csr_wdata   ,  //241:178
					   ms_csr_waddr   ,  //177:166
					   ms_inst        ,  //165:134
					   ms_gr_we       ,  //133:133
					   ms_dest        ,  //132:128
					   ms_final_result,  //127:64
					   ms_pc             //63:0
					   };



assign ms_ready_go    = 1'b1;
assign ms_allowin     = !ms_valid || ms_ready_go && ws_allowin;
assign ms_to_ws_valid = ms_valid && ms_ready_go;
always @(posedge clk) begin
	if (reset | except_flush) begin
		// reset
		ms_valid <= 1'b0;
	end
	else if (ms_allowin) begin
		ms_valid <= es_to_ms_valid;
	end

	if(es_to_ms_valid && ms_allowin) begin
		es_to_ms_bus_r <= es_to_ms_bus;
	end
end

assign ms_pc_to_ws    = ms_pc   ;
assign ms_valid_to_ws = ms_valid;

assign mem_result = (ms_mem_control == 11'b1000_0000_000) ? mem_result_lb :
                    (ms_mem_control == 11'b0100_0000_000) ? mem_result_lh :
                    (ms_mem_control == 11'b0010_0000_000) ? mem_result_lw :
                    (ms_mem_control == 11'b0001_0000_000) ? mem_result_lbu:
                    (ms_mem_control == 11'b0000_1000_000) ? mem_result_lhu:
                    (ms_mem_control == 11'b0000_0000_100) ? mem_result_lwu:
                    (ms_mem_control == 11'b0000_0000_010) ? mem_result_ld :
                    										data_sram_rdata;




// assign ms_final_result = ms_res_from_mem ? mem_result
//                                          : ms_alu_result;

assign ms_final_result =ms_skip_mtime        ? mtime_i   :
						ms_skip_mtimecmp     ? mtimecmp_i: 
						ms_res_from_mem      ? mem_result
                                             : ms_alu_result;


endmodule
